#pragma once

#include <iostream>
#include <functional>
#include <cstring>
#include "LogMessage.hpp"
#include "EventHandler.hpp"
#include "Epoller.hpp"
#include "Socket.hpp"

void SetNonBlocking(int fd)
{
    int fl = fcntl(fd, F_GETFL);
    if (fl == -1)
    {
        lg.LogMessage(Error, "fcntl error, errno: %d, strerror: %s", errno, strerror(errno));
    }
    fcntl(fd, F_SETFL, fl | O_NONBLOCK);
}

// listen套接字的读事件
class Accepter
{
public:
    void ListenAccepter(Socket *listensock, Epoller *epoll, TcpServer *Rector)
    {
        if (listensock == nullptr || epoll == nullptr || Rector == nullptr)
        {
            lg.LogMessage(Warning, "ListenAccept error, TcpSocket: %p Epoll: %p, TcpServer: %p", listensock, epoll, Rector);
            return;
        }

        while (true)
        {
            InetAddr addr;
            // 1. 非阻塞接受新连接
            Socket *newsock = listensock->AcceptConnect(addr);
            if (newsock != nullptr)
            {
                lg.LogMessage(Debug, "get a new link, sockfd: %d", newsock->GetSockfd());
                // 2. 设置新连接为非阻塞
                SetNonBlocking(newsock->GetSockfd());
                // 3. 添加到epoll模型当中
                epoll->AddEpoll(newsock->GetSockfd(), EPOLLIN | EPOLLET);
                // 4. 创建Connect对象
                auto reader = std::bind(&EventHandler::Reader, std::placeholders::_1);
                auto writer = std::bind(&EventHandler::Writer, std::placeholders::_1);
                auto excepter = std::bind(&EventHandler::Excepter, std::placeholders::_1);
                Connect *conn = new Connect(newsock, Rector);
                conn->Establishment(reader, writer, excepter);
                // 5. 添加Connect对象
                Rector->AddConnection(newsock->GetSockfd(), conn);

                lg.LogMessage(Debug, "Add epoll success");
            }
            else 
            {
                if (errno == EAGAIN)
                    break;
                else if (errno == EINTR)
                    continue;
                else 
                {
                    lg.LogMessage(Warning, "Get g new link error");
                }
            }
        }
    }

private:
};